
#include "stdafx.h"
#include "resource.h"
#include "CtxMenu.h"
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <process.h>
#include <errno.h>
#include "SHUtils.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////
// registry key util struct
typedef struct
{
   HKEY  hRootKey;
   LPTSTR lpszSubKey;
   LPTSTR lpszValueName;
   LPTSTR lpszData;
}REGSTRUCT, *LPREGSTRUCT;

STDAPI RegisterFileMenu();
STDAPI UnregisterFileMenu();

/**************************************************************************

	STDAPI DllRegisterServer(void)

	Set the Registry keys for this set of shell/namespace extensions

**************************************************************************/
STDAPI DllRegisterServer(void)
{
	// if we do MFC stuff in an exported fn, call this first!
	AFX_MANAGE_STATE(AfxGetStaticModuleState( ));

	HRESULT h = RegisterFileMenu();

	return h;
}


STDAPI DllUnregisterServer(void)
{
	// if we do MFC stuff in an exported fn, call this first!
	AFX_MANAGE_STATE(AfxGetStaticModuleState( ));

	HRESULT h = UnregisterFileMenu();

	return h;
}


STDAPI RegisterFileMenu()
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState( ));

	HINSTANCE hInst = AfxGetInstanceHandle();

	int      i;
	HKEY     hKey;
	LRESULT  lResult;
	DWORD    dwDisp;
	TCHAR    szSubKey[MAX_PATH];
	TCHAR    szCLSID[MAX_PATH];
	TCHAR    szModule[MAX_PATH];
	LPWSTR   pwszShellExt;

	//get the CLSID in string form
	StringFromIID(CLSID_MyFileCtxMenuID, &pwszShellExt);			    

	if (pwszShellExt) {
		WideCharToLocal(szCLSID, pwszShellExt, ARRAYSIZE(szCLSID));

		//free the string
		LPMALLOC pMalloc;
		CoGetMalloc(1, &pMalloc);
		if(pMalloc)
		{
			pMalloc->Free(pwszShellExt);
			pMalloc->Release();
		}
	}															   

	//get this DLL's path and file name																    
	GetModuleFileName(hInst, szModule, ARRAYSIZE(szModule));

	// these entries have their %s's replaced with CLSID strings,
	// their second entries are replaced with the module's path.
	//register the CLSID entries
	REGSTRUCT ShExClsidEntries[] = {  
              
		// this is the 	HKEY_CLASSES_ROOT/CLSID/<our CLSID> entry. this is where we place info about our shell ext.
		// our CLSID (generated by GUIDGEN) is how the system refers to our shell extension.
		HKEY_CLASSES_ROOT,	TEXT("CLSID\\%s"),					NULL,                   TEXT(SHELLEXNAME),

		// HKEY_CLASSES_ROOT/CLSID/<our CLSID>/InProcServer . here, we tell the system where our DLL is located
		HKEY_CLASSES_ROOT,	TEXT("CLSID\\%s\\InProcServer32"),	NULL,                   TEXT("%s"),

		// HKEY_CLASSES_ROOT/CLSID/<our CLSID>/InProcServer/ThreadingModel = Apartment . this is a standard thing. don't modify it
		HKEY_CLASSES_ROOT,	TEXT("CLSID\\%s\\InProcServer32"),	TEXT("ThreadingModel"), TEXT("Apartment"),

		// end the array
		NULL,                NULL,								NULL,                   NULL};

	for(i = 0; ShExClsidEntries[i].hRootKey; i++) 
   {
		//Create the sub key string.
		wsprintf(szSubKey, ShExClsidEntries[i].lpszSubKey, szCLSID);

		lResult = RegCreateKeyEx(  ShExClsidEntries[i].hRootKey,
								  szSubKey,
								  0,
								  NULL,
								  REG_OPTION_NON_VOLATILE,
								  KEY_WRITE,
								  NULL,
								  &hKey,
								  &dwDisp);

	   if(NOERROR == lResult) 
      {
			TCHAR szData[MAX_PATH];
																						 
			//if necessary, create the value string
			wsprintf(szData, ShExClsidEntries[i].lpszData, szModule);

			lResult = RegSetValueEx(   hKey,
									 ShExClsidEntries[i].lpszValueName,
									 0,
									 REG_SZ,
									 (LPBYTE)szData,
									 lstrlen(szData) + 1);

			RegCloseKey(hKey);

		} else
			return SELFREG_E_CLASS;
   }                                

	// these entries have their %s's replaced with CLSID strings - one per entry, please
	REGSTRUCT OtherShExEntries[] = {  
			// HKEY_CLASSES_ROOT/*/shellex/ContextMenuHandlers/SHELLEXNAME. tell the system that we want our
			// shell extension to handle all files: note the "*". ex. we could easily limit it to JPG files by
			// changing the "*" to ".jpg".
			// our CLSID is placed in the "%s", and so, explorer will take that CLSID, look in HKEY_CLASSES_ROOT/CLSID
			// to find a matching CLSID and use the info in there to find our DLL... whew. 
			HKEY_CLASSES_ROOT,	TEXT("AllFileSystemObjects\\shellex\\ContextMenuHandlers\\"SHELLEXNAME), NULL,		TEXT("%s"),

			// end the array
			NULL,					NULL,								NULL,                   NULL};

	for (i = 0; OtherShExEntries[i].hRootKey; i++) 
   {
		//Create the sub key string.
		wsprintf(szSubKey, OtherShExEntries[i].lpszSubKey, szCLSID);

		lResult = RegCreateKeyEx(  OtherShExEntries[i].hRootKey,
								  szSubKey,
								  0,
								  NULL,
								  REG_OPTION_NON_VOLATILE,
								  KEY_WRITE,
								  NULL,
								  &hKey,
								  &dwDisp);

		if(NOERROR == lResult) {
			TCHAR szData[MAX_PATH];

			//if necessary, create the value string
			wsprintf(szData, OtherShExEntries[i].lpszData, szCLSID);

			lResult = RegSetValueEx(   hKey,
									 OtherShExEntries[i].lpszValueName,
									 0,
									 REG_SZ,
									 (LPBYTE)szData,
									 lstrlen(szData) + 1);

			RegCloseKey(hKey);

		} else
			return SELFREG_E_CLASS;
	}

	//If running on NT, register the extension as approved.
	OSVERSIONINFO  osvi;

	osvi.dwOSVersionInfoSize = sizeof(osvi);
	GetVersionEx(&osvi);

	// NT needs to have shell extensions "approved".
	if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)  
   {
		lstrcpy( szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"));

		lResult = RegCreateKeyEx(  HKEY_LOCAL_MACHINE,
							  szSubKey,
							  0,
							  NULL,
							  REG_OPTION_NON_VOLATILE,
							  KEY_WRITE,
							  NULL,
							  &hKey,
							  &dwDisp);

		if(NOERROR == lResult) 
      {
			TCHAR szData[MAX_PATH];

			//Create the value string.
			lstrcpy(szData, TEXT(SHELLEXNAME));

			lResult = RegSetValueEx(   hKey,
									 szCLSID,
									 0,
									 REG_SZ,
									 (LPBYTE)szData,
									 lstrlen(szData) + 1);

			RegCloseKey(hKey);
		} else
			return SELFREG_E_CLASS;
	}

	return S_OK;
}


/**************************************************************************
**************************************************************************/
STDAPI UnregisterFileMenu(void)
{
	// if we do MFC stuff in an exported fn, call this first!
	AFX_MANAGE_STATE(AfxGetStaticModuleState( ));

	HINSTANCE hInst = AfxGetInstanceHandle();

	int      i;
	LRESULT  lResult;
	TCHAR    szSubKey[MAX_PATH];
	TCHAR    szCLSID[MAX_PATH];
	LPWSTR   pwszShellExt;

	//get the CLSID in string form
	StringFromIID(CLSID_MyFileCtxMenuID, &pwszShellExt);			    

	if (pwszShellExt) {
		WideCharToLocal(szCLSID, pwszShellExt, ARRAYSIZE(szCLSID));

		//free the string
		LPMALLOC pMalloc;						  
		CoGetMalloc(1, &pMalloc);
		if(pMalloc)
		{
			pMalloc->Free(pwszShellExt);
			pMalloc->Release();
		}
	}															   
					    
	// these entries have their %s's replaced with CLSID strings,
	// their second entries are replaced with the module's path.
	//register the CLSID entries
	REGSTRUCT ShExClsidEntries[] = {  

		// HKEY_CLASSES_ROOT/CLSID/<our CLSID>/InProcServer . here, we tell the system where our DLL is located
		HKEY_CLASSES_ROOT,	TEXT("CLSID\\%s\\InProcServer32"),	NULL,                   NULL,

		// this is the 	HKEY_CLASSES_ROOT/CLSID/<our CLSID> entry. this is where we place info about our shell ext.
		// our CLSID (generated by GUIDGEN) is how the system refers to our shell extension.
		HKEY_CLASSES_ROOT,	TEXT("CLSID\\%s"),					NULL,                   NULL,

		// end the array
		NULL,                NULL,								NULL,                   NULL};

	for(i = 0; ShExClsidEntries[i].hRootKey; i++) {
		//Create the sub key string.
		wsprintf(szSubKey, ShExClsidEntries[i].lpszSubKey, szCLSID);

		lResult = RegDeleteKey(  ShExClsidEntries[i].hRootKey,
								  szSubKey);
																			 
		if(NOERROR == lResult) {
		} else
			return SELFREG_E_CLASS;
	}

	// these entries have their %s's replaced with CLSID strings - one per entry, please
	REGSTRUCT OtherShExEntries[] = {  
			// HKEY_CLASSES_ROOT/*/shellex/ContextMenuHandlers/SHELLEXNAME. tell the system that we want our
			// shell extension to handle all files: note the "*". ex. we could easily limit it to JPG files by
			// changing the "*" to ".jpg".
			// our CLSID is placed in the "%s", and so, explorer will take that CLSID, look in HKEY_CLASSES_ROOT/CLSID
			// to find a matching CLSID and use the info in there to find our DLL... whew. 
			HKEY_CLASSES_ROOT,	TEXT("AllFileSystemObjects\\shellex\\ContextMenuHandlers\\"SHELLEXNAME), NULL,		NULL,

			// end the array
			NULL,					NULL,								NULL,                   NULL};

	for (i = 0; OtherShExEntries[i].hRootKey; i++) {
		//Create the sub key string.
		wsprintf(szSubKey, OtherShExEntries[i].lpszSubKey, szCLSID);

		lResult = RegDeleteKey(  OtherShExEntries[i].hRootKey,
								  szSubKey);

		if(NOERROR == lResult) {
		} else
			return SELFREG_E_CLASS;
	}
					    
	//If running on NT, register the extension as approved.
	OSVERSIONINFO  osvi;

	osvi.dwOSVersionInfoSize = sizeof(osvi);
	GetVersionEx(&osvi);

	// NT needs to have shell extensions "approved".
	if (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId)  {
		lstrcpy( szSubKey, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved\\"SHELLEXNAME));


		lResult = RegDeleteKey( HKEY_LOCAL_MACHINE,
								 szSubKey);
	}

	return S_OK;

}
